Bokeh ElementsΒΆ

Elements are the basic building blocks for any HoloViews visualization. These are the objects that can be composed together using the various Container types. Here in this overview, we show an example of how to build each of these Elements directly out of Python or Numpy data structures. An even more powerful way to use them is by collecting similar Elements into a HoloMap, as described in Exploring Data, so that you can explore, select, slice, and animate them flexibly, but here we focus on having small, self-contained examples. Complete reference material for each type can be accessed using our documentation system.

Element types

This class hierarchy shows each of the Element types. Each type is named for the default or expected way that the underlying data can be visualized. E.g., if your data is wrapped into a Surface object, it will display as a 3D surface by default, whereas an Image object will display as a 2D raster image. But please note that the specification and implementation for each Element type does not actually include any such visualization -- the name merely serves as a semantic indication that you ordinarily think of the data as being laid out in that way. The actual plotting is done by a separate plotting subsystem, while the objects themselves focus on storing your data and the metadata needed to describe and use it.

This separation of data and visualization is described in detail in the Options tutorial, which describes all about how to find out the options available for each Element type and change them if necessary, from either Python or IPython Notebook. For convenience, in this tutorial we have specified %output info=True, which will pop up a detailed list and explanation of the available options for visualizing each Element type, after that notebook cell is executed. So, to find out all the options for any of these Element types, just press <Shift-Enter> on the corresponding cell in the live notebook.

The types available:

[``Element``](#Element)
The base class of all ``Elements``.

Charts:

[``Curve``](#Curve)
A continuous relation between a dependent and an independent variable.
[``ErrorBars``](#ErrorBars)
A collection of x-/y-coordinates with associated symmetric or asymmetric errors.
[``Spread``](#Spread)
Just like ErrorBars, Spread is a collection of x-/y-coordinates with associated symmetric or asymmetric errors.
[``Histogram``](#Histogram)
Data collected and binned in a continuous space using specified bin edges.
[``Scatter``](#Scatter)
Discontinuous collection of points indexed over a single dimension.
[``Points``](#Points)
Discontinuous collection of points indexed over two dimensions.
[``SideHistogram``](#SideHistogram)
Histogram binning data contained by some other ``Element``.

Rasters:

[``Raster``](#Raster)
The base class of all rasters containing two-dimensional arrays.
[``HeatMap``](#HeatMap)
Raster displaying sparse, discontinuous data collected in a two-dimensional space.
[``Image``](#Image)
Raster containing a two-dimensional array covering a continuous space (sliceable).
[``RGB``](#RGB)
Raster of 3 (R,G,B) or 4 (R,G,B,Alpha) color channels.

Tabular Elements:

[``ItemTable``](#ItemTable)
Ordered collection of key-value pairs (ordered dictionary).
[``Table``](#Table)
Collection of arbitrary data with arbitrary key and value dimensions.

Annotations:

[``VLine``](#VLine)
Vertical line annotation.
[``HLine``](#HLine)
Horizontal line annotation.
[``Spline``](#Spline)
Bezier spline (arbitrary curves).
[``Text``](#Text)
Text annotation on an ``Element``.

Paths:

[``Path``](#Path)
Collection of paths.
[``Contours``](#Contours)
Collection of paths, each with an associated value.
[``Polygons``](#Polygons)
Collection of filled, closed paths with an associated value.
[``Bounds``](#Bounds)
Box specified by corner positions.
[``Box``](#Bounds)
Box specified by center position, radius, and aspect ratio.
[``Ellipse``](#Ellipse)
Ellipse specified by center position, radius, and aspect ratio.

Element

The basic or fundamental types of data that can be visualized.

Element is the base class for all the other HoloViews objects shown in this section.

All Element objects accept data as the first argument to define the contents of that element. In addition to its implicit type, each element object has a group string defining its category, and a label naming this particular item, as described in the Introduction.

When rich display is off, or if no visualization has been defined for that type of Element, the Element is presented in {type}.{group}.{label} format:

In [1]:
import holoviews as hv
hv.notebook_extension(bokeh=True)
%output backend='bokeh'
hv.Element(None, group='Value', label='Label')
HoloViewsJS, BokehJS successfully loaded in this cell.
Out[1]:
:Element

In addition, Element has key dimensions (kdims), value dimensions (vdims), and constant dimensions (cdims) to describe the semantics of indexing within the Element, the semantics of the underlying data contained by the Element, and any constant parameters associated with the object, respectively. Dimensions are described in the Introduction.

The remaining Element types each have a rich, graphical display as shown below.

Chart Elements

Visualization of a dependent variable against an independent variable

The first large class of Elements is the Chart elements. These objects are by default indexable and sliceable along the x-axis, but not the y-axis, because they are intended for data values y measured for a given x value. However two key dimensions may be supplied to allow 2D indexing on these types. By default the data is expected to be laid out on a single key dimension x, with the data values ranging over a single value dimension y.

The data itself maybe supplied in one of three formats, however internally the data will always be held as a numpy array of shape (N, D), where N is the number of samples and D the number of dimensions. The accepted formats are:

1) As a numpy array of shape (N, D).
2) As a list of length N containing tuples of length D.
3) As a tuple of length D containing iterables of length N.

Curve

In [2]:
import numpy as np
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
hv.Curve(points)
Out[2]:

A Curve is a set of values provided for some set of keys from a continuously indexable 1D coordinate system.

ErrorBars

In [3]:
np.random.seed(7)
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
errors = [(0.1*i, np.sin(0.1*i), np.random.rand()/2) for i in np.linspace(0, 100, 11)]
hv.Curve(points) * hv.ErrorBars(errors)
Out[3]:

ErrorBars is a set of x-/y-coordinates with associated error values, which may be either symmetric or asymmetric and thus can be supplied as an Nx3 or Nx4 array or any of the alternative constructors Chart Elements allow.

In [4]:
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
errors = [(0.1*i, np.sin(0.1*i), np.random.rand()/2, np.random.rand()/4) for i in np.linspace(0, 100, 11)]
hv.Curve(points) * hv.ErrorBars(errors, vdims=['y', 'yerrneg', 'yerrpos'])
Out[4]:

Spread

Spread elements have the same data format as the ErrorBars element, name x- and y-values with associated symmetric or assymetric errors.

Symmetric
In [5]:
np.random.seed(42)
xs = np.linspace(0, np.pi*2, 20)
err = 0.2+np.random.rand(len(xs))
hv.Spread((xs, np.sin(xs), err))
Out[5]:
Asymmetric
In [6]:
%%opts Spread (fill_color='indianred')
xs = np.linspace(0, np.pi*2, 20)
hv.Spread((xs, np.sin(xs), 0.1+np.random.rand(len(xs)), 0.1+np.random.rand(len(xs))),
          vdims=['y', 'yerrneg', 'yerrpos'])
Out[6]:

Histogram

In [7]:
np.random.seed(1)
data = [np.random.normal() for i in range(10000)]
frequencies, edges = np.histogram(data, 20)
hv.Histogram(frequencies, edges)
Out[7]:

Almost all Element types may be projected onto a polar axis by supplying projection='polar' as a plot option.

In [8]:
%%opts Histogram [projection='polar' show_grid=True]
data = [np.random.rand()*np.pi*2 for i in range(100)]
frequencies, edges = np.histogram(data, 20)
hv.Histogram(frequencies, edges, kdims=['Angle'])
WARNING:root:Options: Invalid options ['show_grid'], valid options are: ['apply_extents', 'apply_extents', 'apply_ranges', 'apply_ranges', 'bgcolor', 'bgcolor', 'border', 'border', 'callbacks', 'callbacks', 'default_tools', 'default_tools', 'fontsize', 'fontsize', 'height', 'height', 'invert_axes', 'invert_axes', 'invert_xaxis', 'invert_xaxis', 'invert_yaxis', 'invert_yaxis', 'lod', 'lod', 'logx', 'logx', 'logy', 'logy', 'normalize', 'normalize', 'projection', 'projection', 'shared_axes', 'shared_axes', 'shared_datasource', 'shared_datasource', 'show_legend', 'show_legend', 'show_title', 'show_title', 'title_format', 'title_format', 'tools', 'tools', 'width', 'width', 'xaxis', 'xaxis', 'xrotation', 'xrotation', 'xticks', 'xticks', 'yaxis', 'yaxis', 'yrotation', 'yrotation', 'yticks', 'yticks']
Out[8]:

Scatter

In [9]:
%%opts Scatter (color='k', marker='s', s=10)
np.random.seed(42)
points = [(i, np.random.random()) for i in range(20)]
hv.Scatter(points) + hv.Scatter(points)[12:20]
Out[9]:

The marker shape specified above can be any supported by matplotlib, e.g. s, d, or o; the other options select the color and size of the marker.

Points

In [10]:
np.random.seed(12)
points = np.random.rand(50,2)
hv.Points(points) + hv.Points(points)[0.6:0.8,0.2:0.5]
Out[10]:

As you can see, Points is very similar to Scatter, but it is sliceable in both x and y, not just x, and so the right-hand plots are different for these two Elements. Even though they can take the same input data, the Points object treats both x and y as key_dimensions, while Scatter has a single key_dimension x and a single value_dimension y:

In [11]:
for o in [hv.Points(points,name="Points "), hv.Scatter(points,name="Scatter")]:
    for d in ['key','value']:
        print("%s %s_dimensions: %s " % (o.name, d, o.dimensions(d,label=True)))
Points  key_dimensions: ['x', 'y'] 
Points  value_dimensions: [] 
Scatter key_dimensions: ['x'] 
Scatter value_dimensions: ['y'] 

Thus the Scatter object expresses a dependent relationship between x and y, making it useful for combining with other similar Chart types, while the Points object expresses the relationship of two independent keys x and y with optional vdims (zero in this case), which makes Points objects meaningful to combine with the Raster types below.

Of course, the vdims need not be empty for Points; here is an example with two additional quantities for each point, as value_dimensions z and α visualized as the color and size of the dots, respectively:

In [12]:
%%opts Points [color_index=2 size_index=3 scaling_factor=50] (cmap='jet')
np.random.seed(10)
data = np.random.rand(100,4)

points = hv.Points(data, vdims=['z', 'alpha'])
points + points[0.3:0.7, 0.3:0.7].hist()
Out[12]:

SideHistogram

The .hist method conveniently adjoins a histogram to the side of any Chart, Surface, or Raster component, as well as many of the container types (though it would be reporting data from one of these underlying Element types). For a Raster using color or grayscale to show values (below), the side histogram doubles as a color bar or key.

In [13]:
import numpy as np
np.random.seed(42)
points = [(i, np.random.normal()) for i in range(800)]
hv.Scatter(points).hist()
Out[13]:

Raster Elements

A collection of raster image types

The second large class of Elements is the raster elements. Like Points and unlike the other Chart elements, Raster Elements live in a two-dimensional space. For the Image, RGB, and HSV elements, the coordinates of this two-dimensional space are defined in a continuously indexable coordinate system.

Raster

A Raster is the base class for image-like Elements, but may be used directly to visualize 2D arrays using a color map. The coordinate system of a Raster is the raw indexes of the underlying array, with integer values always starting from (0,0) in the top left, with default extents corresponding to the shape of the array. The Image subclass visualizes similarly, but using a continuous Cartesian coordinate system suitable for an array that represents some underlying continuous region.

In [14]:
x,y = np.mgrid[-50:51, -50:51] * 0.1
hv.Raster(np.sin(x**2+y**2))
Out[14]:

HeatMap

A HeatMap displays like a typical raster image, but the input is a dictionary indexed with two-dimensional keys, not a Numpy array. As many rows and columns as required will be created to display the values in an appropriate grid format. Values unspecified are left blank, and the keys can be any Python datatype (not necessarily numeric). One typical usage is to show values from a set of experiments, such as a parameter space exploration, and many other such visualizations are shown in the Containers and Exploring Data tutorials. Each value in a HeatMap is labeled explicitly , and so this component is not meant for very large numbers of samples. With the default color map, high values (in the upper half of the range present) are colored orange and red, while low values (in the lower half of the range present) are colored shades of blue.

In [15]:
data = {(chr(65+i),chr(97+j)):i*j for i in range(5) for j in range(5) if i!=j}
hv.HeatMap(data)
Out[15]:

Image

Like Raster, a HoloViews Image allows you to view 2D arrays using an arbitrary color map. Unlike Raster, an Image is associated with a 2D coordinate system in continuous space, which is appropriate for values sampled from some underlying continuous distribution (as in a photograph or other measurements from locations in real space). Slicing, sampling, etc. on an Image all use this continuous space, whereas the corresponding operations on a Raster work on the raw array coordinates.

In [16]:
x,y = np.mgrid[-50:51, -50:51] * 0.1
bounds=(-1,-1,1,1)   # Coordinate system: (left, bottom, top, right)

(hv.Image(np.sin(x**2+y**2),   bounds=bounds) 
 + hv.Image(np.sin(x**2+y**2), bounds=bounds)[-0.5:0.5, -0.5:0.5])
Out[16]:

Notice how, because our declared coordinate system is continuous, we can slice with any floating-point value we choose. The appropriate range of the samples in the input numpy array will always be displayed, whether or not there are samples at those specific floating-point values.

It is also worth noting that the name Image can clash with other common libraries, which is one reason to avoid unqualified imports like from holoviews import *. For instance, the Python Imaging Libray provides an Image module, and IPython itself supplies an Image class in IPython.display. Python namespaces allow you to avoid such problems, e.g. using from PIL import Image as PILImage or using import holoviews as hv and then hv.Image(), as we do in these tutorials.

RGB

The RGB element is an Image that supports red, green, blue channels:

In [17]:
x,y = np.mgrid[-50:51, -50:51] * 0.1

r = 0.5*np.sin(np.pi  +3*x**2+y**2)+0.5
g = 0.5*np.sin(x**2+2*y**2)+0.5
b = 0.5*np.sin(np.pi/2+x**2+y**2)+0.5

hv.RGB(np.dstack([r,g,b]))
Out[17]:

You can see how the RGB object is created from the original channels:

In [18]:
%%opts Image (cmap='gray')
hv.Image(r,label="R") + hv.Image(g,label="G") + hv.Image(b,label="B")
Out[18]:

RGB also supports an optional alpha channel, which will be used as a mask revealing or hiding any Elements it is overlaid on top of:

In [19]:
%%opts Image (cmap='gray')
mask = 0.5*np.sin(0.2*(x**2+y**2))+0.5
rgba = hv.RGB(np.dstack([r,g,b,mask]))

bg = hv.Image(0.5*np.cos(x*3)+0.5, label="Background") * hv.VLine(x=0,label="Background")

overlay = bg*rgba
overlay.label="RGBA Overlay"

bg + hv.Image(mask,label="Mask") + overlay
Out[19]:

Tabular Elements

General data structures for holding arbitrary information

ItemTable

An ItemTable is an ordered collection of key, value pairs. It can be used to directly visualize items in a tabular format where the items may be supplied as an OrderedDict or a list of (key,value) pairs. A standard Python dictionary can be easily visualized using a call to the .items() method, though the entries in such a dictionary are not kept in any particular order, and so you may wish to sort them before display. One typical usage for an ItemTable is to list parameter values or measurements associated with an adjacent Element.

In [20]:
hv.ItemTable([('Age', 10), ('Weight',15), ('Height','0.8 meters')])
Out[20]:

Table

A table is more general than an ItemTable, as it allows multi-dimensional keys and multidimensional values.

In [21]:
keys =   [('M',10), ('M',16), ('F',12)]
values = [(15, 0.8), (18, 0.6), (10, 0.8)]
table = hv.Table(zip(keys,values), 
                 kdims = ['Gender', 'Age'], 
                 vdims=['Weight', 'Height'])
table
Out[21]:

Note that you can use select using tables, and once you select using a full, multidimensional key, you get an ItemTable (shown on the right):

In [22]:
table.select(Gender='M') + table.select(Gender='M', Age=10)
Out[22]:

The Table is used as a common data structure that may be converted to any other HoloViews data structure using the TableConversion class. A similar principle holds when converting data from Pandas DataFrames to HoloViews objects using the optional Pandas support.

The functionality of the TableConversion class may be conveniently accessed using the .to property, which should have its own tutorial someday, but hopefully this will get the idea across:

In [23]:
table.select(Gender='M').to.curve(kdims=["Age"], vdims=["Weight"])
Out[23]:

Annotation Elements

Useful information that can be overlaid onto other components

Annotations are components designed to be overlaid on top of other Element objects. To demonstrate annotation and paths, we will be drawing many of our elements on top of an RGB Image:

In [24]:
scene = hv.RGB.load_image('../assets/penguins.png')

VLine and HLine

In [25]:
scene * hv.VLine(-0.05) + scene * hv.HLine(-0.05)
Out[25]:

Spline

The Spline annotation is used to draw Bezier splines using the same semantics as matplotlib splines. In the overlay below, the spline is in dark blue and the control points are in light blue.

In [26]:
points = [(-0.3, -0.3), (0,0), (0.25, -0.25), (0.3, 0.3)]
codes = [1,4,4,4]
scene * hv.Spline((points,codes)) * hv.Curve(points)
Out[26]:

Text

In [27]:
scene * hv.Text(0, 0.2, 'Adult\npenguins')
Out[27]:

Paths

Line-based components that can be overlaid onto other components

Paths are a subclass of annotations that involve drawing line-based components on top of other elements. Internally Path Element types hold a list of Nx2 arrays, specifying the x/y-coordinates along each path. The data may be supplied in a number of ways however

1) A list of Nx2 numpy arrays.
2) A list of lists containing x/y coordinate tuples.
3) A tuple containing an array of length N with the x-values and a
   second array of shape NxP, where P is the number of paths.
4) A list of tuples each containing separate x and y values.

Path

A Path object is actually a collection of paths which can be arbitrarily specified. Although there may be multiple unconnected paths in a single Path object, they will all share the same style. Only by overlaying multiple Path objects do you iterate through the defined color cycle (or any other style options that have been defined).

In [28]:
angle = np.linspace(0, 2*np.pi, 100)
baby = list(zip(0.15*np.sin(angle),  0.2*np.cos(angle)-0.2))

adultR = [(0.25, 0.45), (0.35,0.35), (0.25, 0.25), (0.15, 0.35), (0.25, 0.45)]
adultL = [(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4),(-0.3, 0.4)]

scene * hv.Path([adultL, adultR, baby]) * hv.Path([baby])
Out[28]:

Contours

A Contours object is similar to Path object except each of the path elements is associated with a numeric value, called the level. Sadly, our penguins are too complicated to give a simple example so instead we will simply mark the first couple of rings of our earlier ring pattern:

In [29]:
x,y = np.mgrid[-50:51, -50:51] * 0.1

def circle(radius, x=0, y=0):
    angles = np.linspace(0, 2*np.pi, 100)
    return np.array( list(zip(x+radius*np.sin(angles), y+radius*np.cos(angles))))

hv.Image(np.sin(x**2+y**2)) * hv.Contours([circle(0.22)], level=0) * hv.Contours([circle(0.33)], level=1)
Out[29]:

Polygons

A Polygons object is similar to a Contours object except that each supplied path is closed and filled. Just like Contours, optionally a level may be supplied, the Polygons will then be colored according to the supplied cmap. Non-finite values such as np.NaN or np.inf will default to the supplied facecolor.

Polygons with values can be used as heatmaps with arbitrary shapes.

In [30]:
%%opts Polygons (cmap='hot' line_color='black' line_width=2)
np.random.seed(35)
hv.Polygons([np.random.rand(4,2)], level=0.5) *\
hv.Polygons([np.random.rand(4,2)], level=1.0) *\
hv.Polygons([np.random.rand(4,2)], level=1.5) *\
hv.Polygons([np.random.rand(4,2)], level=2.0)
Out[30]:

Polygons without a value are useful as annotation, but also allow us to draw arbitrary shapes.

In [31]:
def rectangle(x=0, y=0, width=1, height=1):
    return np.array([(x,y), (x+width, y), (x+width, y+height), (x, y+height)])

(hv.Polygons([rectangle(width=2), rectangle(x=6, width=2)])(style={'fill_color': '#a50d0d'})
* hv.Polygons([rectangle(x=2, height=2), rectangle(x=5, height=2)])(style={'fill_color': '#ffcc00'})
* hv.Polygons([rectangle(x=3, height=2, width=2)])(style={'fill_color': 'red'}))
Out[31]:

Bounds

A bounds is a rectangular area specified as a tuple in (left, bottom, right, top) format. It is useful for denoting a region of interest defined by some bounds, whereas Box (below) is useful for drawing a box at a specific location.

In [32]:
scene * hv.Bounds(0.2) * hv.Bounds((0.45, 0.45, 0.2, 0.2))
Out[32]:

A Box is similar to a Bounds except you specify the box position, width, and aspect ratio instead of the coordinates of the box corners. An Ellipse is specified just as for Box, but has a round shape.

In [33]:
scene * hv.Box(    -0.25, 0.3, 0.3, aspect=0.5) * hv.Box(    0, -0.2, 0.1) + \
scene * hv.Ellipse(-0.25, 0.3, 0.3, aspect=0.5) * hv.Ellipse(0, -0.2, 0.1)
Out[33]:

Download this notebook from GitHub (right-click to download).